Normally, the byte-compiler does not actually
execute the forms in a file it compiles. For example, if a file
contains (setq foo t), the act of compiling it will
not actually set foo to t. This is true
even if the setq was a top-level form (i.e., not
enclosed in a defun or other form). Sometimes,
though, you would like to have certain top-level forms evaluated
at compile-time. For example, the compiler effectively evaluates
defmacro forms at compile-time so that later parts
of the file can refer to the macros that are defined.
This form controls when the body forms are evaluated. The situations list may contain any set of the symbols
compile,load, andeval(or their long-winded ANSI equivalents,:compile-toplevel,:load-toplevel, and:execute).The
eval-whenform is handled differently depending on whether or not it is being compiled as a top-level form. Specifically, it gets special treatment if it is being compiled by a command such asbyte-compile-filewhich compiles files or buffers of code, and it appears either literally at the top level of the file or inside a top-levelprogn.For compiled top-level
eval-whens, the body forms are executed at compile-time ifcompileis in the situations list, and the forms are written out to the file (to be executed at load-time) ifloadis in the situations list.For non-compiled-top-level forms, only the
evalsituation is relevant. (This includes forms executed by the interpreter, forms compiled withbyte-compilerather thanbyte-compile-file, and non-top-level forms.) Theeval-whenacts like aprognifevalis specified, and likenil(ignoring the body forms) if not.The rules become more subtle when
eval-whens are nested; consult Steele (second edition) for the gruesome details (and some gruesome examples).Some simple examples:
;; Top-level forms in foo.el: (eval-when (compile) (setq foo1 'bar)) (eval-when (load) (setq foo2 'bar)) (eval-when (compile load) (setq foo3 'bar)) (eval-when (eval) (setq foo4 'bar)) (eval-when (eval compile) (setq foo5 'bar)) (eval-when (eval load) (setq foo6 'bar)) (eval-when (eval compile load) (setq foo7 'bar))When foo.el is compiled, these variables will be set during the compilation itself:
foo1 foo3 foo5 foo7 ; `compile'When foo.elc is loaded, these variables will be set:
foo2 foo3 foo6 foo7 ; `load'And if foo.el is loaded uncompiled, these variables will be set:
foo4 foo5 foo6 foo7 ; `eval'If these seven
eval-whens had been, say, inside adefun, then the first three would have been equivalent toniland the last four would have been equivalent to the correspondingsetqs.Note that
(eval-when (load eval) ...)is equivalent to(progn ...)in all contexts. The compiler treats certain top-level forms, likedefmacro(sort-of) andrequire, as if they were wrapped in(eval-when (compile load eval) ...).
Emacs includes two special forms related to
eval-when. One of these,
eval-when-compile, is not quite equivalent to any
eval-when construct and is described below.
The other form, (eval-and-compile ...), is
exactly equivalent to ‘(eval-when
(compile load eval) ...)’ and so is not
itself defined by this package.
The forms are evaluated at compile-time; at execution time, this form acts like a quoted constant of the resulting value. Used at top-level,
eval-when-compileis just like ‘eval-when (compile eval)’. In other contexts,eval-when-compileallows code to be evaluated once at compile-time for efficiency or other reasons.This form is similar to the ‘#.’ syntax of true Common Lisp.
The form is evaluated at load-time; at execution time, this form acts like a quoted constant of the resulting value.
Early Common Lisp had a ‘#,’ syntax that was similar to this, but ANSI Common Lisp replaced it with
load-time-valueand gave it more well-defined semantics.In a compiled file,
load-time-valuearranges for form to be evaluated when the .elc file is loaded and then used as if it were a quoted constant. In code compiled bybyte-compilerather thanbyte-compile-file, the effect is identical toeval-when-compile. In uncompiled code, botheval-when-compileandload-time-valueact exactly likeprogn.(defun report () (insert "This function was executed on: " (current-time-string) ", compiled on: " (eval-when-compile (current-time-string)) ;; or '#.(current-time-string) in real Common Lisp ", and loaded on: " (load-time-value (current-time-string))))Byte-compiled, the above defun will result in the following code (or its compiled equivalent, of course) in the .elc file:
(setq --temp-- (current-time-string)) (defun report () (insert "This function was executed on: " (current-time-string) ", compiled on: " '"Wed Jun 23 18:33:43 1993" ", and loaded on: " --temp--))